home *** CD-ROM | disk | FTP | other *** search
- /*
- File: TMP_CreateConfig.c
-
- Contains: The non-resident code for our template configurator class
-
- This code is not intended to implement an actual
- working configurator. It comes with no warranty,
- express or implied, as to it's suitability for your
- own configuration implementation.
-
- */
-
- #ifndef __TMP_CONFIG__
- #include "TMP_Config.h"
- #endif
- #if TMPCONFIG_USES_ASLM
- #include <LibraryManagerUtilities.h>
- #else
- #include <CodeFragments.h>
- #endif
-
- /*******************************************************************************
- ** Globals
- ********************************************************************************/
-
- static TMPConfigurator* gConfigData = NULL;
-
- /*
- * Size of preference structures for our various protocol
- * preferences.
- */
- static UInt16 gPrefLens[] =
- {
- sizeof(Prot1Prefs),
- sizeof(Prot2Prefs),
- sizeof(Prot3Prefs)
- };
-
- static char* gProtNames[] = { kProtocolList, 0 };
-
- /*******************************************************************************
- ** ReadMyPreferences
- **
- ** You must supply this function to read your preferences.
- ********************************************************************************/
-
- static OSStatus ReadMyPreferences(MyPreferences **prefs, OTPortRef link_id)
- {
- #pragma unused(prefs)
- #pragma unused(link_id)
- return noErr;
- }
-
- /*******************************************************************************
- ** DestroyMyPreferences
- **
- ** You must supply this function to destroy your preferences.
- ********************************************************************************/
-
- static void DestroyMyPreferences(MyPreferences *prefs)
- {
- #pragma unused(prefs)
- }
-
- /*******************************************************************************
- ** MyCreateConfiguration
- **
- ** This is the state machine function that we use to open the control stream.
- ********************************************************************************/
-
- static pascal void MyCreateConfiguration(OTStateMachine* sm)
- {
- TMPOpenInfo* info = (TMPOpenInfo*)OTSMGetClientData(sm);
- AConfiguration* aCfig = info->fConfig;
-
- while ( true )
- {
- switch ( OTSMGetState(sm) )
- {
- /*
- * For the purposes of this template, we just assume you have some function
- * that will read your preferences from somewhere.
- */
- case 0:
- {
- /*
- * Just in case there are already prefs present, destroy them.
- */
- if ( aCfig->fPrefs != NULL )
- {
- DestroyMyPreferences(aCfig->fPrefs);
- aCfig->fPrefs = NULL;
- }
- /*
- * This function reads in the prefs, creates the prefs structure and stores
- * it in the pointer passed. If it can't read the prefs, it can either
- * create a set of default preferences, or just return an error.
- */
- sm->fResult = ReadMyPreferences(&aCfig->fPrefs, info->fConfig->fLinkID);
-
- if ( sm->fResult == kOTNoError )
- break;
- /*
- * Now, we're creating our network layer - we want a separate copy for each link
- * that we're created over. Some protocols might want this, and others won't. For
- * instance, TCP/IP keeps a single TCP/IP, and routes between all links. For
- * AppleTalk, we treat each stack as linearly independent. To do this, we need
- * STREAMS to think that this is a different DDP than all the other DDPs that exist
- * over other link layers. To do this, we register DDP as a private pseud-port.
- * This gives each copy of DDP over a different link a different name so that STREAMS
- * believes it's a different driver.
- */
- OTSMSetState(sm, 1);
- /*
- * Only do this if we don't already have a name, which means we're already registered.
- */
- if ( aCfig->fNetworkName[0] == 0 )
- {
- OTPortRecord record;
-
- OTMemzero(&record, sizeof(record));
- /*
- * We're a pseudo-device, so we're going to let Open Transport assign us a
- * port ref, because we don't care what it is
- */
- record.fRef = OTCreatePortRef(0, kOTPseudoDevice, 0, 0);
- /*
- * Flag that we're a private port so clients scanning the port list know this
- */
- record.fInfoFlags = kOTPortIsPrivate;
- record.fCapabilities = 0;
- /*
- * Let Open Transport provide us with a port name
- */
- record.fPortName[0] = 0;
- /*
- * Set up that we have 1 child port, our link layer. This allows the
- * OTIsDependentPort function to realize that we depend on this link
- * layer.
- */
- record.fChildPorts = &aCfig->fLinkID;
- record.fNumChildPorts = 1;
- /*
- * Copy in the name of our stream module. For the purposes of illustration,
- * we assume it's the kProt1ID protocol
- */
- OTStrCopy(record.fModuleName, gProtNames[kProt1ID]);
- /*
- * Register the port. If an error - split
- */
- sm->fResult = OTRegisterPort(&record, NULL);
- if ( sm->fResult != kOTNoError )
- break;
- /*
- * Save off our port ref, and the name Open Transport gave us.
- */
- aCfig->fOurID = record.fRef;
- OTStrCopy(aCfig->fNetworkName, record.fPortName);
- }
- /*
- * Now open the stream by our port name. If it returns true, then the call
- * is already done, and we should reenter the state machine to keep going.
- */
- if ( !OTSMOpenStream(sm, aCfig->fNetworkName, info->fOpenFlags) )
- return;
- continue;
- }
-
- case 1:
- {
- /*
- * If opening our control stream failed - split
- * Otherwise, save off the StreamRef.
- */
- if ( sm->fResult != kOTNoError )
- break;
-
- aCfig->fCtlStream = (StreamRef)sm->fCookie;
-
- /* -----------------------------------------------------------------
- Get our Preferences and download them to the control Stream.
- ----------------------------------------------------------------- */
-
- OTSMSetState(sm, 2);
-
- info->fIoctlInfo.ic_cmd = kMyConfigureIoctl;
- info->fIoctlInfo.ic_timout = 15;
- info->fIoctlInfo.ic_len = gPrefLens[0];
- info->fIoctlInfo.ic_dp = (char*)aCfig->fPrefs->fPrefs[0];
- if ( !OTSMIoctl(sm, aCfig->fCtlStream, I_STR, (long) &info->fIoctlInfo) )
- return;
- continue;
- }
-
- //
- // The following states send more IOCTLs to our network layer to set up the preferences
- //
- #define kPrefsState 1
-
- case 2:
- case 3:
- {
- size_t state = OTSMGetState(sm);
-
- if ( sm->fResult < 0 )
- break;
-
- OTSMSetState(sm, state + 1);
- info->fIoctlInfo.ic_cmd = kMyConfigureIoctl + state - kPrefsState;
- info->fIoctlInfo.ic_timout = 15;
- info->fIoctlInfo.ic_len = gPrefLens[state - kPrefsState];
- info->fIoctlInfo.ic_dp = (char*)aCfig->fPrefs->fPrefs[state - kPrefsState];
- if ( !OTSMIoctl(sm, aCfig->fCtlStream, I_STR, (long) &info->fIoctlInfo) )
- return;
- continue;
- }
-
- /*
- * Now, let's create the link layer
- */
- case 4:
- {
- OTSMSetState(sm, 5);
- if ( sm->fResult < 0 )
- break;
- /*
- * We call OTSMCreateStream instead of OTSMOpenStream because the child may
- * be arbitrarily complex, and just "opening" the child may be a big mistake.
- * We let the rest of the Open Transport infrastructure figure out how to
- * create our child, and just return us the StreamRef.
- */
- if ( !OTSMCreateStream(sm, OTCfigGetChild(info->fCfig, 0), info->fOpenFlags) )
- return;
- continue;
- }
-
- /*
- * Now, let's I_LINK the driver module under our protocol. We need to do this as
- * an I_LINK, because if we just push the network layer on top, we don't get the
- * cloning effect that we want. Remember that you can only bind 1 time to the link
- * layer, and the network layer has to de-multiplex incoming packets to the other
- * copies of the network layer. Otherwise, each network layer instance would have to
- * bind to the same address to the link layer. While Open Transport allows this, it
- * would be grossly inefficient.
- */
- case 5:
- {
- OTSMSetState(sm, 6);
- if ( sm->fResult != kOTNoError )
- break;
- /*
- * Now link the driver under our control stream. Note that the
- * StreamRef of the driver is in sm->fCookie.
- */
- info->fTheStream = (StreamRef)sm->fCookie;
- if ( !OTSMIoctl(sm, aCfig->fCtlStream, I_LINK, (long) info->fTheStream) )
- return;
- }
-
- /*
- * Check the result of the I_LINK, then close the driver, then create a
- * 2nd stream, where we're going to push our "helper" module (for AppleTalk,
- * this would be the NBP module) over that second stream.
- */
- case 6:
- {
- OTSMSetState(sm, 7);
- /*
- * Be very careful here - we can't check sm->fResult != kOTNoError, since
- * IOCTLs can return positive values (in the case of I_LINKs, its the muxid).
- */
- if ( sm->fResult < 0 )
- break;
- /*
- * Now that the driver is linked, we can close it. That way, when we
- * close the control stream, the driver will automatically be closed.
- * Otherwise, we would have to keep the driver StreamRef around until
- * we closed down.
- */
- OTStreamClose(info->fTheStream);
- /*
- * Open a 2nd copy of our network layer. This is a clone of our
- * original copy of the protocol.
- */
- if ( !OTSMOpenStream(sm, aCfig->fNetworkName, info->fOpenFlags) )
- return;
- continue;
- }
- /*
- * Save it as the helper stream, and turn signals on on the control stream, so that
- * we can get event notification
- */
- case 7:
- {
- OTSMSetState(sm, 8);
- if ( sm->fResult != kOTNoError )
- break;
-
- aCfig->fHelperStream = (StreamRef)sm->fCookie;
-
- if ( !OTSMIoctl(sm, aCfig->fCtlStream, I_SETSIG,
- S_INPUT | S_RDNORM | S_RDBAND | S_HIPRI | S_OUTPUT | S_WRNORM |
- S_WRBAND | S_MSG | S_ERROR | S_HANGUP | S_BANDURG) )
- return;
- continue;
- }
- /*
- * Now, we push our helper module onto the 2nd network layer
- */
- case 8:
- {
- OTSMSetState(sm, 9);
- if ( sm->fResult != kOTNoError )
- break;
- /*
- * Install our notifier into the stream, then do the push onto the
- * helper stream.
- * Note that the "controller" code put the proc pointer into the
- * TMPOpenInfo structure so that we can install the notifier, even though
- * the "controller" is the one to get notifications.
- */
- OTStreamInstallNotifier(aCfig->fCtlStream, info->fNotifyProc, aCfig);
- if ( !OTSMIoctl(sm, aCfig->fHelperStream, I_PUSH, (long) gProtNames[kProt3ID]) )
- return;
- continue;
- }
- /*
- * Here, the helper push is done. We are fully configured if it worked.
- */
- case 9:
- {
- if ( sm->fResult < 0 )
- break;
-
- //
- // Update our status and store the configuration onto our global list
- // of configurations.
- //
- aCfig->fStatus = kIsInUse;
- OTAddFirst(&gConfigData->fGlobal->fConfigs, &aCfig->fMyLink);
- sm->fResult = kOTNoError;
- sm->fCode = kStreamOpenEvent;
- /*
- * Complete the state machine back to our client
- */
- OTSMPopCallback(sm);
- OTSMComplete(sm);
- return;
- }
-
- }
- //
- // If we break out of the switch - an error occurred and the fResult
- // field is already filled out. Make sure the code is a kStreamOpenEvent
- // and complete to our client (which is our controller library).
- //
- sm->fCode = kStreamOpenEvent;
- OTSMPopCallback(sm);
- OTSMComplete(sm);
- return;
- }
- }
-
- /*******************************************************************************
- ** OTCreateMyConfiguration
- **
- ** This is the function we export to the other part of our configurator. It is
- ** code we only need while we're plumbing. If the code is small, there is
- ** probably no reason to split it out into a separate shared library, but we've
- ** done it for illustration's sake.
- ********************************************************************************/
-
- Boolean OTCreateMyConfiguration(TOTConfigurator* cfigor, OTStateMachine* sm)
- {
- TMPConfigurator* data = (TMPConfigurator*)OTGetConfiguratorUserData(cfigor);
- TMPOpenInfo* info = (TMPOpenInfo*)OTSMGetClientData(sm);
- OTConfiguration* kid = OTCfigGetChild(info->fCfig, 0);
- /*
- * Save off the configuration info
- */
- gConfigData = data;
- /*
- * Get our child, and set up our link ID. Of course, if we're a link layer,
- * getting our child is usually not done, but then, for a link layer, this
- * 3rd library is not often needed anyway.
- */
- info->fConfig->fLinkID = OTCfigGetPortRef(kid);
-
- return OTSMCallStateProc(sm, MyCreateConfiguration, 0);
- }
-
- /*******************************************************************************
- ** This is our init and teardown routine
- ********************************************************************************/
-
- pascal void TeardownTMPCreateConfig(void)
- {
- CloseOpenTransport();
- }
-
- #if GENERATING68K
- #pragma segment A5Init
- #endif
-
- #if TMPCONFIG_USES_CFM
-
- pascal OSErr InitTMPCreateConfig(CFragInitBlock* ibp)
- {
- #pragma unused(ibp)
- return InitOpenTransport();
- }
-
- #else
-
- void InitTMPCreateConfig()
- {
- OSStatus err = InitOpenTransport();
- if ( err != kOTNoError )
- {
- Fail(err, NULL);
- }
- }
-
- #endif
-
- #if GENERATING68K
- #pragma segment Main
- #endif
-